package com.config;

import com.invocation.attribute.RoleAttributeFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleHierarchyVoter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.stereotype.Controller;

import java.util.Collections;

/**
 * 对 {@link EnableGlobalMethodSecurity} 简要拆解测试
 * https://docs.spring.io/spring-security/reference/5.8/servlet/authorization/secure-objects.html
 *
 * 这种配置方式比较繁琐，有过度设计的嫌疑
 * 推荐使用简化之后的 方法拦截
 * @see  MethodInterceptorConfig
 */
@Configuration
public class SecurityObjectConfig {

    @Bean
    public Advisor securityObjectAdvisor(){
        Pointcut pointcut = new AnnotationMatchingPointcut(Controller.class, PreAuthorize.class,true);

        return new DefaultPointcutAdvisor(pointcut,methodSecurityInterceptor());
    }

    @Bean
    public MethodSecurityInterceptor methodSecurityInterceptor() {
        MethodSecurityInterceptor securityInterceptor = new MethodSecurityInterceptor();
        securityInterceptor.setAccessDecisionManager(new AffirmativeBased(
                Collections.singletonList(
                        accessDecisionVoter()
                )
        ));


        securityInterceptor.setSecurityMetadataSource(
                new PrePostAnnotationSecurityMetadataSource(
                        new RoleAttributeFactory()
                )
        );
        return securityInterceptor;
    }

    @Bean
    public AccessDecisionVoter<Object> accessDecisionVoter() {
        RoleHierarchyImpl RoleHierarchy = new RoleHierarchyImpl();
        RoleHierarchy.setHierarchy("ROLE_admin > ROLE_stuff\n" +
                "ROLE_stuff > ROLE_user\n" +
                "ROLE_user > ROLE_guest\n");
        return new RoleHierarchyVoter(RoleHierarchy);
    }


}
